%{
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>

#include "settings.h"
#include "module.h"
#include "sim.h"
#include "types.h"

extern int yylex();
extern "C" void yyerror (const char []);
extern setts identifiers[];

using namespace std;

#define MAX_INT_QUEUE_SIZE 3000
int int_array[MAX_INT_QUEUE_SIZE];
int int_array_index = 0;

module_t module_index_array[MAX_INT_QUEUE_SIZE];
int module_array_index = 0;

%}

%union {
	int ident;
    int boolean;
	int enumeration;
	long long number;
	char * text;
    module_t module_index;
}

%token <ident> 		 IDENTIFIER
%token <boolean>     BOOLEAN
%token <enumeration> ENUMERATION
%token <number>		 NUMBER
%token <text>        TEXT
%token ALLOCATE COLON COMMA LBRACKET RBRACKET LBRACE RBRACE INVALID
%token RPARA LPARA LSHIFT
%token MODULE_TIERS 
%token <module_index> MODULE_INDEX

%%

config_list: 
 config_entry
 | config_list config_entry
 ;

config_entry:
 IDENTIFIER COLON BOOLEAN        { *((bool *)identifiers[$1].pointer) = $3; }
 | IDENTIFIER COLON ENUMERATION  { *((int *)identifiers[$1].pointer) = $3; }
 | IDENTIFIER COLON NUMBER       
{
    if (!strcmp (identifiers[$1].name, "sesc_nsim") || 
        !strcmp (identifiers[$1].name, "sesc_rabbit"))
    {
        *((signed long long int *)identifiers[$1].pointer) = $3; 
    }
    else if (!strcmp (identifiers[$1].name, "debug_addr")) 
    {
        *((unsigned long long int *)identifiers[$1].pointer) = $3 & 0xffffffff; 
    }
    else
    {
        *((int *)identifiers[$1].pointer) = $3; 
    }
}
 | IDENTIFIER COLON LPARA NUMBER LSHIFT NUMBER RPARA
{
    int num;
    
    num = ($4 << $6);
    *((int *)identifiers[$1].pointer) = num;
}
 | IDENTIFIER LBRACKET NUMBER RBRACKET COLON ALLOCATE
{
    assert (sizeof (node_t) == sizeof (int));
    
    if ((*(int**)identifiers[$1].pointer) != NULL)
    {
    	delete [] (*(int**)identifiers[$1].pointer);
    }
    *((int **)identifiers[$1].pointer) = new int[$3];
}
 | IDENTIFIER LBRACKET NUMBER RBRACKET COLON LBRACE argument_list RBRACE 
{
	assert( $3 < MAX_INT_QUEUE_SIZE);
	
    if ((*(int**)identifiers[$1].pointer) != NULL)
    {
    	delete [] (*(int**)identifiers[$1].pointer);
    }
    *((int **)identifiers[$1].pointer) = new int[$3];
    
	for( int i = 0; i < $3; i++)
	{
		(*(int **)identifiers[$1].pointer)[$3 - i - 1] = int_array[i];
    }
	int_array_index = 0;
}
 | MODULE_TIERS COLON LBRACE module_index_list RBRACE
{
    //TODO
}
 ;

argument_list:
 NUMBER                       { int_array[int_array_index++] = $1; }
 | ENUMERATION                { int_array[int_array_index++] = $1; }
 | NUMBER COMMA argument_list { int_array[int_array_index++] = $1; }
 | ENUMERATION COMMA argument_list { int_array[int_array_index++] = $1; }

module_index_list:
MODULE_INDEX         { module_index_array[module_array_index++] = $1; }
| MODULE_INDEX COMMA module_index_list { module_index_array[module_array_index++] = $1; }

%%
